package xyz.wadewhy.basicstest.json;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonIgnoreType;
import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.SneakyThrows;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

class JackSonTest {
    public static void main(String[] args) {
//        pojoToJson();
//        jsonToPojo();
//        jsonFileToPojo();
//        jsonToMap();
//        jsonToList();
//        jsonToListIgnoreField();
//        jsonToPojoNotNull();
//        pojoDateToLongJson();
//        pojoDateToStringJson();
        jsonNode();
    }

    @SneakyThrows
    public static void pojoToJson() {
        Car car = new Car("奔驰", "black", 1);
        ObjectMapper objectMapper = new ObjectMapper();
        //输出
        objectMapper.writeValue(new FileOutputStream("car.json"), car);
        String carJson = objectMapper.writeValueAsString(car);
        System.out.println(carJson);

    }

    /**
     * string to pojo
     */
    @SneakyThrows
    public static void jsonToPojo() {
        String carJson = "{\"name\":\"奔驰\",\"color\":\"black\"}";
        ObjectMapper objectMapper = new ObjectMapper();
        Car car = objectMapper.readValue(carJson, Car.class);
        System.out.println(car);
    }

    /**
     * file to pojo
     */
    @SneakyThrows
    public static void jsonFileToPojo() {
        ObjectMapper objectMapper = new ObjectMapper();
        File file = new File("car.json");
        Car car = objectMapper.readValue(file, Car.class);
        System.out.println(car);
    }

    @SneakyThrows
    public static void jsonToMap() {
        String jsonObject = "{\"brand\":\"ford\", \"doors\":5}";
        ObjectMapper objectMapper = new ObjectMapper();
        Map<String, Object> jsonMap =
                objectMapper.readValue(jsonObject, new TypeReference<Map<String, Object>>() {
                });
        System.out.println(jsonMap);
    }

    /**
     * json to list
     */
    @SneakyThrows
    public static void jsonToList() {
        String jsonList = "[{\"name\":\"奔驰\",\"color\":\"black\"},{\"name\":\"奔驰\",\"color\":\"black\"}]";
        ObjectMapper objectMapper = new ObjectMapper();
        List<Car> cars = objectMapper.readValue(jsonList, new TypeReference<List<Car>>() {
        });
        for (Car car : cars) {
            System.out.println(car);
        }
    }

    /**
     * FAIL_ON_UNKNOWN_PROPERTIES 忽略多出的字段
     */
    @SneakyThrows
    public static void jsonToListIgnoreField() {
        //json 字段比pojo 字段多一个 xxx
        String jsonList = "[{\"name\":\"奔驰\",\"color\":\"black\",\"xxx\":1},{\"name\":\"奔驰\",\"color\":\"black\",\"xxx\":1}]";
        ObjectMapper objectMapper = new ObjectMapper();
        // 通过这个忽略多出来的字段
        objectMapper.configure(
                DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        List<Car> cars = objectMapper.readValue(jsonList, new TypeReference<List<Car>>() {
        });
        for (Car car : cars) {
            System.out.println(car);
        }
    }

    /**
     * FAIL_ON_NULL_FOR_PRIMITIVES
     */
    @SneakyThrows
    public static void jsonToPojoNotNull() {
        String carJsonNull = "{\"name\":\"奔驰\",\"doors\":null}";
        ObjectMapper objectMapper = new ObjectMapper();
        //加上配置，基础类型如果为null 就报错
        objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, true);
        Car car = objectMapper.readValue(carJsonNull, Car.class);
        System.err.println(car);
    }

    /**
     * pojo date field to long
     */
    @SneakyThrows
    public static void pojoDateToLongJson() {
        Phone phone = new Phone(new Date(), "iphone");
        ObjectMapper objectMapper = new ObjectMapper();
        String value = objectMapper.writeValueAsString(phone);
        System.out.println(value);
    }

    /**
     * pojo date field to long
     */
    @SneakyThrows
    public static void pojoDateToStringJson() {
        Phone phone = new Phone(new Date(), "iphone");
        ObjectMapper objectMapper = new ObjectMapper();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        objectMapper.setDateFormat(dateFormat);
        String value = objectMapper.writeValueAsString(phone);
        System.out.println(value);
    }

    /**
     * 当不知道具体的对象时，JsonNode
     */
    @SneakyThrows
    public static void jsonNode() {
        String carJson = "{\"name\":\"奔驰\",\"color\":\"black\"}";
        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode jsonNode = objectMapper.readValue(carJson, JsonNode.class);
        System.out.println(jsonNode);
        JsonNode name = jsonNode.findValue("name");
        System.err.println(name);
        Object o = objectMapper.treeToValue(jsonNode, Car.class);
        System.err.println(o);
    }
}

@Data
@AllArgsConstructor
@NoArgsConstructor
class Car {
    private String name;
    private String color;
    private int doors;
}

@Data
@AllArgsConstructor
@NoArgsConstructor
class Phone {
    private Date createTime;
    private String name;
}

@Data
@AllArgsConstructor
@NoArgsConstructor
//忽略字段
@JsonIgnoreProperties({"A1", "A2"})
class People {
    /**
     * name 转为Name
     */
    @JsonSetter("Name")
    private String name;
    /**
     * 忽略字段
     * 在将JSON读取到Java对象中以及将Java对象写入JSON时，都将忽略该属性。
     */
    @JsonIgnore
    private String nikeName;
    private Integer age;
    private Date birthDay;
    private String A1;
    private String A2;
    private Float A3;
    private Double A4;
    /**
     * JsonIgnoreType,Address整个被忽略
     */
    @JsonIgnoreType
    public static class Address {
        public String streetName  = null;
        public String houseNumber = null;
        public String zipCode     = null;
        public String city        = null;
        public String country     = null;
    }

}